package topoMesh;

import hdgeom.primitives.Vec3D;

import java.util.ArrayList;

import processing.core.PVector;

//basic splitting rule
class RuleSplit extends Rule {
	TopoMeshNode[] nodeNodes;
	TopoMeshNode[] edgeNodes;
	TopoMeshNode[] faceNodes;
	TopoMesh mesh;
	TopoMesh newMesh;

	RuleSplit() {

	}

	RuleSplit(float extrudeNode, float extrudeEdge, float extrudeFace) {
		this.extrudeFactorNode = extrudeNode;
		this.extrudeFactorEdge = extrudeNode;
		this.extrudeFactorFace = extrudeFace;
	}

	public TopoMesh replace(TopoMesh mesh) {
		// TODO Auto-generated method stub
		this.mesh = mesh;
		newMesh = new TopoMesh();
		collectNodes();
		compose();
		newMesh.construct();
		return newMesh;
	}

	// collecting the new Nodes
	public void collectNodes() {
		nodeNodes = new TopoMeshNode[mesh.getNNodes()];
		edgeNodes = new TopoMeshNode[mesh.getNEdges()];
		faceNodes = new TopoMeshNode[mesh.getNFaces()];
		for (int i = 0; i < mesh.getNFaces(); i++) {
			TopoMeshFace face = mesh.getFace(i);
			TopoMeshNode node = getFacePt(face);
			faceNodes[i] = node;
			node.setId(newMesh.getNNodes());
			newMesh.addNode(node);
		}

		ArrayList<TopoMeshEdge> edges = mesh.getEdges();
		for (int i = 0; i < edges.size(); i++) {
			TopoMeshEdge edge = edges.get(i);
			TopoMeshNode node = getEdgePt(edge);
			edgeNodes[i] = node;
			node.setId(newMesh.getNNodes());
			newMesh.addNode(node);
		}

		for (int i = 0; i < mesh.getNNodes(); i++) {
			TopoMeshNode n = mesh.getNode(i);
			TopoMeshNode node = getNodePt(n);
			nodeNodes[i] = node;
			node.setId(newMesh.getNNodes());
			newMesh.addNode(node);
		}
	}

	public float getFaceExtrude(TopoMeshFace face) {
		return 1;
	}

	public float getEdgeExtrude(TopoMeshEdge edge) {
		return 1;
	}

	public float getNodeExtrude(TopoMeshNode node) {
		return 1;
	}

	public void compose() {
		for (int i = 0; i < mesh.getNFaces(); i++) {
			TopoMeshFace face = mesh.getFace(i);
			for (int ii = 0; ii < face.getNNodes(); ii++) {
				TopoMeshNode n1 = face.getNode(ii);
				TopoMeshNode n2 = face.getNode(ii + 1);
				TopoMeshNode n3 = face.getNode(ii + 2);
				TopoMeshEdge e1 = n1.getEdge(n2);
				TopoMeshEdge e2 = n2.getEdge(n3);
				TopoMeshNode[] newNodes = new TopoMeshNode[4];
				newNodes[0] = (edgeNodes[e1.getId()]);
				newNodes[1] = (nodeNodes[n2.getId()]);
				newNodes[2] = (edgeNodes[e2.getId()]);
				newNodes[3] = (faceNodes[face.getId()]);
				TopoMeshFace newFace = new TopoMeshFace(newNodes);
				newFace.setComment(face.getComment());
				newFace.fix = face.fix;
				newMesh.addFace(newFace);
			}
		}
	}

	public TopoMeshNode getNodePt(TopoMeshNode n) {
		TopoMeshNode node = new TopoMeshNode(n);
		node.setComment(n.getComment());
		if (n.fix) {
			return node;
		}
		Vec3D normal = n.getNormal();
		normal.mult(getNodeExtrude(n) * extrudeFactorNode);
		node.add(normal);
		return node;
	}

	public TopoMeshNode getFacePt(TopoMeshFace face) {
		PVector center = face.getCenter();
		TopoMeshNode node = new TopoMeshNode(center.x, center.y, center.z);
		node.setComment(face.getComment());
		if (!face.fix) {
			Vec3D normal = face.getNormal();
			normal.mult(getFaceExtrude(face) * extrudeFactorFace);
			node.add(normal);
		}
		return node;
	}

	public TopoMeshNode getEdgePt(TopoMeshEdge edge) {
		TopoMeshNode n1 = edge.getNode1();
		TopoMeshNode n2 = edge.getNode2();
		TopoMeshNode newNode = new TopoMeshNode(edge.getCenter());
		if (n1.getComment() == 1 && n2.getComment() == 1) {
			newNode.setComment(1);
			return newNode;
		}
		Vec3D normal = edge.getNormal();
		normal.mult(getEdgeExtrude(edge) * extrudeFactorEdge);
		newNode.add(normal);
		return newNode;
	}

}